#pragma once
#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <fcntl.h>
#include "../comm/util.hpp"
#include "../comm/log.hpp"

namespace ns_runner
{
    using namespace ns_util;
    using namespace ns_log;

    class runner
    {
    public:
        runner(){}
        ~runner(){}
    private:
        static void SetProcResource(const rlim_t cpu_limit, const rlim_t mem_limit)
        {
            struct rlimit r_cpu;
            r_cpu.rlim_cur = cpu_limit;
            r_cpu.rlim_max = RLIM_INFINITY;
            setrlimit(RLIMIT_CPU, &r_cpu);

            struct rlimit r_mem;
            r_mem.rlim_cur = mem_limit * 1024; //转化为KB
            r_mem.rlim_max = RLIM_INFINITY;
            setrlimit(RLIMIT_AS, &r_mem);
        }
    public:
        static int Run(const std::string& file_name, const int cpu_limit, const int mem_limit)
        {
            pid_t pid = fork();
            const std::string excute = PathUtil::ExeFile(file_name);
            const std::string _stdin = PathUtil::StdinFile(file_name);
            const std::string _stdout = PathUtil::StdoutFile(file_name);
            const std::string _stderr = PathUtil::StderrFile(file_name);

            umask(0);
            int stdin_fd = open(_stdin.c_str(), O_CREAT | O_RDONLY, 0644);
            int stdout_fd = open(_stdout.c_str(), O_CREAT | O_WRONLY, 0644);
            int stderr_fd = open(_stderr.c_str(), O_CREAT | O_WRONLY, 0644);
            if(stdin_fd < 0 || stdout_fd < 0 || stderr_fd < 0)
            {
                LOG(ERROR) << "打开文件失败" << std::endl;
                return -1;
            }

            if(pid < 0)
            {
                close(stdin_fd);
                close(stdout_fd);
                close(stderr_fd);

                LOG(ERROR) << "open file failed " << std::endl;

                return -2;
            }
            else if(pid == 0)
            {
                //将输出信息显示到文件中
                dup2(stdin_fd, 0);
                dup2(stdout_fd, 1);
                dup2(stderr_fd, 2);

                SetProcResource(cpu_limit, mem_limit);
                execl(excute.c_str(), excute.c_str(), nullptr);
                LOG(DEBUG) << "excute failed" << std::endl;

                return 1;
            }
            else
            {
                close(stdin_fd);
                close(stdout_fd);
                close(stderr_fd);

                int status = 0;
                waitpid(pid, &status, 0);

                //程序运行异常，是因为信号 
                LOG(INFO) << "result signo " << (status & 0x7F) << std::endl;

                return status & 0X7F;
            }
        }
    };
}